/*!***************************************************
 * @file: func_app.c
 * @brief: 好友等功能的逻辑应用代码
 * @author: ITHAO 
 * @date: 2018.12.9
 * @note: 
 ****************************************************/
#include <stdio.h>
#include <string.h>


#include "func.h"
#include "func_app.h"
#include "comm_protocol_core.h"
#include "client_management.h"
#include "debug.h"

static int load_user_friend(char *account, struct friend *friend);
static int add_friend(char *new_friend_account, char *owner_account);
static int remove_friend(char *friend_account, char *owner_account);


/**
 * @brief	聊天功能应用函数  
 * @param	data_packet--需要被处理的数据
 *          clientfd--通信fd
 *          online_user--在线用户数据
 * @return	void
 * @note:   此函数被工作线程调用
 */
void chat_app(struct data_packet data_packet,
              int clientfd, struct online_user *online_user)
{
    int ret = 0;
    struct data_packet recv_data_packet;
    struct data_packet *send_data_packet;
    struct comm_core comm;
    struct chat_packet chat_packet_tmp;
    char send_name[NAME_MAX_LENGTH];
    int friend_fd = -1;

     if (!online_user) {
        DEBUG("PARAM NULL!\r\n");
        return;
    }

    init_chat_packet(&chat_packet_tmp);
    recv_data_packet = data_packet;
    comm_core_init(&comm);
    comm.dev.cmd = COMM_SEND;
    send_data_packet = &comm.data.send_data_packet;
    send_data_packet->cmd_type = recv_data_packet.cmd_type;
    comm.data.sendfd = clientfd;

    /*聊天消息需要4个参数--发送者账号、接收者账号、时间、消息*/
    if (!recv_data_packet.data[0] || !recv_data_packet.data[1] ||
        !recv_data_packet.data[2] || !recv_data_packet.data[3]) {
        send_data_packet->ack = SHORT_OF_DATA_ACK;
        return;
    }

    ret = is_account_exist((char *)recv_data_packet.data[0], send_name);
    if (ret == FAIL) {
        send_data_packet->ack = CHAT_SENDACCOUNT_NOT_EXIST_ACK;
         comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
         return;
    }

    ret = is_account_exist((char *)recv_data_packet.data[1], NULL);
    if (ret == FAIL) {
        send_data_packet->ack = CHAT_RECVACCOUNT_NOT_EXIST_ACK;
         comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
         return;
    }

    ret = is_online_user((char *)recv_data_packet.data[1],
                         online_user, &friend_fd);
    if (ret == FAIL) {
        strncpy(chat_packet_tmp.send_name, send_name, NAME_MAX_LENGTH);
        strncpy(chat_packet_tmp.send_account,
                (char *)recv_data_packet.data[0],
                ACCOUNT_MAX_LENGTH);
        strncpy(chat_packet_tmp.recv_account,
                (char *)recv_data_packet.data[1],
                ACCOUNT_MAX_LENGTH);
        strncpy(chat_packet_tmp.time,
                (char *)recv_data_packet.data[2], 26);
        strncpy(chat_packet_tmp.msg, 
                (char *)recv_data_packet.data[3],
                strlen((char *)recv_data_packet.data[3]));
        save_chat_packet(&chat_packet_tmp);
    } else {
        comm.data.sendfd = friend_fd;
        send_data_packet->data[0] = (uint8 *)send_name;
        send_data_packet->data[1] = recv_data_packet.data[0];
        send_data_packet->data[2] = recv_data_packet.data[2];
        send_data_packet->data[3] = recv_data_packet.data[3];
        comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
        comm.data.sendfd = clientfd;
        send_data_packet->data[0] = NULL;
        send_data_packet->data[1] = NULL;
        send_data_packet->data[2] = NULL;
        send_data_packet->data[3] = NULL;
    }

    send_data_packet->ack = CHAT_SEND_SUCCESS_ACK;
    comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    comm_core_destory(&comm);
}


/**
 * @brief	好友功能应用函数  
 * @param	data_packet--需要被处理的数据
 *          clientfd--通信fd
 *          online_user--在线用户数据
 * @return	void
 * @note:   此函数被工作线程调用
 */
void friend_app(struct data_packet data_packet,
                int clientfd, struct online_user *online_user)
{
    int ret = 0;
    struct data_packet recv_data_packet;
    struct data_packet *send_data_packet;
    struct comm_core comm;
    struct friend friend;
    int count = 0;
    int send_count = 0;
    char *owner_account = NULL;
    char *friend_account = NULL;
    char friend_name[NAME_MAX_LENGTH];
    char owner_name[NAME_MAX_LENGTH];
    char friend_num[5];
    int friend_clientfd = -1;

    if (!online_user) {
        DEBUG("PARAM NULL!\r\n");
        return;
    }

    recv_data_packet = data_packet;
    comm_core_init(&comm);
    comm.dev.cmd = COMM_SEND;
    send_data_packet = &comm.data.send_data_packet;
    send_data_packet->cmd_type = recv_data_packet.cmd_type;
    send_data_packet->cmd = recv_data_packet.cmd;
    comm.data.sendfd = clientfd;

    switch (recv_data_packet.cmd) {
        /*加载用户的好友信息*/
        case LOAD_FRIEND_CMD:
            /*加载用户信息需要一个信息--需要加载用户的账号*/
            if (!recv_data_packet.data[0]) {
                send_data_packet->ack = SHORT_OF_DATA_ACK;
                break;
            }
            owner_account = (char *)recv_data_packet.data[0];

            ret = load_user_friend(owner_account, &friend);
            if (ret < 0) {
                 send_data_packet->ack = LOAD_FAIL_ACK;
                 break;
            }
            if (ret == FUNCAPP_OWNERACCOUNT_NOT_EXIST) {
                send_data_packet->ack = LOAD_ACCOUNT_NOT_EXIST_ACK;
                break;
            }
            if (ret == FAIL) {
                send_data_packet->ack = LOAD_NO_OWNER_INFO_ACK;
                break;
            }

            /*加载后将好友信息一个一个发过去*/
            send_data_packet->ack = LOAD_SENDING_ACK;
            for (count = 0; count < MAX_FRIEND_NUM; count++) {
                if (friend.info[count].used_flag == 1) {
                    ret = is_online_user(friend.info[count].account,
                                         online_user, NULL);
                    if (ret == TRUE)
                       send_data_packet->data[0] = (uint8 *)"1";
                    else
                       send_data_packet->data[0] = (uint8 *)"0";

                       send_data_packet->data[1] = (uint8 *)friend.info[count].name;
                       send_data_packet->data[2] = (uint8 *)friend.info[count].account;
                    comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
                    send_count ++;
                    if (send_count == friend.friend_num)
                        break;
                }
            }

            /*将好友数量转换为字符串，然后再发过去*/
            sprintf(friend_num,
                     "%d", friend.friend_num);
            send_data_packet->data[0] = (uint8 *)friend_num;
            send_data_packet->ack = LOAD_SUCCESS_ACK;
            break;

        case ADD_FRIEND_CMD:
            /*添加好友需要两个信息--主用户账号，好友账号*/
            if (!recv_data_packet.data[0] || !recv_data_packet.data[1]) {
                send_data_packet->ack = SHORT_OF_DATA_ACK;
                break;
            }
            owner_account = (char *)recv_data_packet.data[0];
            friend_account = (char *)recv_data_packet.data[1];

            ret = add_friend(friend_account, owner_account);
            if (ret < 0) {
                 send_data_packet->ack = ADD_FAIL_ACK;
                 break;
            }
            if (ret == FUNCAPP_OWNERACCOUNT_NOT_EXIST) {
                send_data_packet->ack = ADD_OWNERACCOUNT_NOT_EXIST_ACK;
                break;
            }
            if (ret == FUNCAPP_FRIENDACCOUNT_NOT_EXIST) {
                send_data_packet->ack = ADD_FRIENDACCOUNT_NOT_EXIST_ACK;
                break;
            }
            if (ret == FUNCAPP_EXCEED_FRIEND_NUM) {
                send_data_packet->ack = ADD_EXCEED_FRIEND_NUM;
                break;
            }
            if (ret == FUNCAPP_IS_FRIEND_ALREADY) {
                send_data_packet->ack = ADD_IS_FRIEND_ALREADY_ACK;
                break;
            }

            /*添加成功后，让对方也成为自己的好友*/
            ret = add_friend(owner_account, friend_account);
            if (ret != TRUE) {
                /*好友添加主用户失败，主用户撤回加好友操作，并发送对应错误*/
                remove_friend(friend_account, owner_account);
                send_data_packet->ack = ADD_FRIEND_ADD_OWNER_FAIL_ACK;
                break;
            }

            /*好友互相添加成功，判断好友是否在线，在线则告诉好友有新好友*/
            ret = is_online_user(friend_account,
                             online_user, &friend_clientfd);
            if (ret == TRUE) {
                /*获取当前用户的昵称*/
                is_account_exist(owner_account, owner_name);
                comm.data.sendfd = friend_clientfd;
                send_data_packet->ack = ADD_GET_NEW_FRIEND_ACK;
                send_data_packet->data[0] = (uint8 *)owner_name;
                send_data_packet->data[1] = (uint8 *)owner_account;
                comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);

                send_data_packet->data[0] = (uint8 *)"1";
                comm.data.sendfd = clientfd;
            } else 
                send_data_packet->data[0] = (uint8 *)"0";

            is_account_exist(friend_account, friend_name);
            send_data_packet->data[1] = (uint8 *)friend_name;
            send_data_packet->ack = ADD_SUCCESS_ACK;
            break;

        case REMOVE_FRIEND_CMD:
            /*删除好友信息需要两个信息--主用户账号，好友账号*/
            if (!recv_data_packet.data[0] || !recv_data_packet.data[1]) {
                send_data_packet->ack = SHORT_OF_DATA_ACK;
                break;
            }
            owner_account = (char *)recv_data_packet.data[0];
            friend_account = (char *)recv_data_packet.data[1];

            ret = remove_friend(friend_account, owner_account);
            if (ret < 0) {
                send_data_packet->ack = REMOVE_FAIL_ACK;
                break;
            }
            if (ret == FUNCAPP_OWNERACCOUNT_NOT_EXIST) {
                send_data_packet->ack = REMOVE_OWERACCOUNT_NOT_EXIST_ACK;
                break;
            }
            if (ret == FUNCAPP_FRIENDACCOUNT_NOT_EXIST) {
                send_data_packet->ack = REMOVE_FRIENDACCOUNT_NOT_EXIST_ACK;
                break;
            }
            if (ret == FUNCAPP_NO_OWNER_INFO) {
                send_data_packet->ack = REMOVE_NOT_FRIEND_ACK;
                break;
            }
            if (ret == FUNCAPP_NOT_FRIEND) {
                send_data_packet->ack = REMOVE_NOT_FRIEND_ACK;
                break;
            }

            /*删除成功后让对方也删除自己*/
            ret = remove_friend(owner_account, friend_account);
            if (ret != TRUE) {
                /*好友删除主用户失败*/
                add_friend(friend_account ,owner_account);
                send_data_packet->ack = REMOVE_FRIEND_RMOVE_OWNER_FAIL_ACK;
                break;
            }

            /*互相删除成功，判断好友是否在线，在线时发送删除好友消息*/
            ret = is_online_user(friend_account,
                             online_user, &friend_clientfd);
            if (ret == TRUE) {
                comm.data.sendfd = friend_clientfd;
                send_data_packet->ack = REMOVE_LOSE_FRIEND_ACK;
                send_data_packet->data[0] = (uint8 *)owner_account;
                comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);

                send_data_packet->data[0] = NULL;
                comm.data.sendfd = clientfd;
            }

            send_data_packet->ack = REMOVE_SUCCESS_ACK;
            break;

        default:
            send_data_packet->ack = WRONG_CMD_ACK;
            break;
    }
    comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
}


/**
 * @brief	加载指定用户的好友表
 *          判断用户是否已经注册   
 * @param	account--需要加载好友表的用户账号
 *          clientfd--用于通信的socketfd    
 * @return	-FUNCAPP_PARAM_NULL_ERR        入口参数空
 * 
 *          FAIL                            没有对应用户信息
 *          TRUE                            获取成功
 *          FUNCAPP_OWNERACCOUNT_NOT_EXIST  账号未注册
 */

static int load_user_friend(char *account, struct friend *friend)
{
    int ret;

    if (!account || !friend) {
        DEBUG("PARAM NULL!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }
    if (strlen(account) == 0) {
        DEBUG("PARAM NULL!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }

    ret = is_account_exist(account, NULL);
    if (ret == FAIL)
        return FUNCAPP_OWNERACCOUNT_NOT_EXIST;

    ret = load_friend(account, friend);

    return ret;
}

/**
 * @brief	将指定用户加入好友表，
 *          判断好友和用户是否已经注册         
 * @param	new_friend--新好友的的信息结构体
 *          owner_account--好友表拥有者用户账号
 * @return	ret                                 对应的错误参数
 * 
 *          TRUE                                添加成功
 *          FUNCAPP_OWNERACCOUNT_NOT_EXIST      拥有者账号未注册
 *          FUNCAPP_FRIENDACCOUNT_NOT_EXIST     好友账号未注册
 *          FUNCAPP_EXCEED_FRIEND_NUM           好友数量满
 *          FUNCAPP_IS_FRIEND_ALREADY           已经是好友
 */
static int add_friend(char *new_friend_account, char *owner_account)
{
    int ret;
    struct friend_info friend_info;

    if (!new_friend_account || !owner_account) {
        DEBUG("PARAM NULL!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }

    ret = is_account_exist(owner_account, NULL);
    if (ret == FAIL)
        return FUNCAPP_OWNERACCOUNT_NOT_EXIST;
    ret = is_account_exist(new_friend_account, friend_info.name);
    if (ret == FAIL)
        return FUNCAPP_FRIENDACCOUNT_NOT_EXIST;

    strncpy(friend_info.account, new_friend_account, ACCOUNT_MAX_LENGTH);

    ret = device_add_friend(friend_info, owner_account);
    if (ret < 0) {
        DEBUG("ADD FRIEND ERR, RET IS --%d\r\n", ret);
        return ret;
    } 
    if (ret == FUNC_EXCEED_FRIEND_NUM)
        return FUNCAPP_EXCEED_FRIEND_NUM;
    if (ret == FUNC_IS_FRIEND_ALREADY)
        return FUNCAPP_IS_FRIEND_ALREADY;

    return TRUE;
}


/**
 * @brief	将指定用户加入好友表，
 *          判断好友和用户是否已经注册         
 * @param	new_friend--新好友的的信息结构体
 *          owner_account--好友表拥有者用户账号
 * @return	ret                                 对应的错误返回值
 * 
 *          TRUE                                添加成功
 *          FUNCAPP_OWNERACCOUNT_NOT_EXIST      拥有者账号未注册
 *          FUNCAPP_FRIENDACCOUNT_NOT_EXIST     好友账号未注册
 *          FUNCAPP_NO_OWNER_INFO               没有用户信息
 *          FUNCAPP_NOT_FRIEND                  不是好友
 */
static int remove_friend(char *friend_account, char *owner_account)
{
    int ret;

    if (!friend_account || !owner_account) {
        DEBUG("PARAM NULL!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }

    ret = is_account_exist(owner_account, NULL);
    if (ret == FAIL)
        return FUNCAPP_OWNERACCOUNT_NOT_EXIST;
    ret = is_account_exist(friend_account, NULL);
    if (ret == FAIL)
        return FUNCAPP_FRIENDACCOUNT_NOT_EXIST;

    ret = device_remove_friend(friend_account, owner_account);
    if (ret < 0)
        return ret;
    if (ret == FUNC_NO_OWNER_INFO)
        return FUNCAPP_NO_OWNER_INFO;
    if (ret == FUNC_NOT_FRIEND)
        return FUNCAPP_NOT_FRIEND;

    return TRUE;
}